package com.mohan.system.manage.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mohan.calligraphy.constant.CalligraphyHttpStatus;
import com.mohan.calligraphy.constant.CalligraphyStatus;
import com.mohan.calligraphy.constant.Constant;
import com.mohan.calligraphy.dto.SystemUserRegistry;
import com.mohan.calligraphy.exception.BusinessException;
import com.mohan.calligraphy.util.BeanUtil;
import com.mohan.system.manage.entity.*;
import com.mohan.system.manage.mapper.UserMapper;
import com.mohan.system.manage.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.security.SecurityUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统用户 服务实现类
 * </p>
 *
 * @author mohan
 * @since 2022-11-24
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private IUserRoleService userRoleService;
    @Resource
    private IRoleService roleService;
    @Resource
    private IMenuService menuService;
    @Resource
    private IRoleMenuService roleMenuService;

    @Override
    public User getUserInfoByUserName(String username) {
        User user = getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
        if (user == null) {
            throw new BusinessException(CalligraphyHttpStatus.CalligraphyErrorMessage.USER_NOT_FOUND);
        }
        return user;
    }

    @Override
    public String login(SystemUserRegistry userRegistry) {
        // 获取subject对象
        Subject subject = SecurityUtils.getSubject();
        // 封装token
        UsernamePasswordToken token = new UsernamePasswordToken(userRegistry.getUsername(), userRegistry.getPassword());
        // 使用login方法进行登录
        try {
            subject.login(token);
        } catch (UnknownAccountException e) {
            // 用户没有找到
            throw new BusinessException(CalligraphyHttpStatus.CalligraphyErrorMessage.USER_NOT_FOUND);
        } catch (IncorrectCredentialsException e) {
            throw new BusinessException(CalligraphyHttpStatus.CalligraphyErrorMessage.PASSWORD_ERROR);
        }
        return SecurityUtils.getSubject().getSession().getId().toString();
    }

    @Override
    public void register(SystemUserRegistry userRegistry) {
        User user = new User();
        BeanUtils.copyProperties(userRegistry, user);
        user.setCreateTime(LocalDateTime.now());
        user.setSalt(Constant.SYSTEM_USER_SALT);
        user.setStatus(CalligraphyStatus.SystemStatus.NORMAL.getId().byteValue());
        // 采用三次加密 + MD5的方式
        Md5Hash md5Hash = new Md5Hash(userRegistry.getPassword(), Constant.SYSTEM_USER_SALT, 3);
        String passwordMd5Hash = md5Hash.toHex();
        user.setPassword(passwordMd5Hash);
        save(user);
    }

    @Override
    public List<String> userRoles(String userName) {
        User user = getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, userName).select(User::getUserId));
        // 获取角色ids
        List<Long> roleIds = userRoleService
                .list(new LambdaQueryWrapper<UserRole>()
                        .eq(UserRole::getUserId, user.getUserId()))
                .stream()
                .map(UserRole::getRoleId)
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(roleIds)) {
            return null;
        }
        return roleService.list(new LambdaQueryWrapper<Role>()
                                .in(Role::getRoleId, roleIds)
                                .select(Role::getRoleName))
                .stream()
                .map(Role::getRoleName)
                .collect(Collectors.toList());
    }

    @Override
    public List<Menu> getRoleInfo(List<String> roleIds) {
        if (!CollectionUtils.isEmpty(roleIds)) {
            throw new BusinessException(CalligraphyHttpStatus.CalligraphyErrorMessage.ROLE_COLLOCTION_EMPTY);
        }
        // 获取角色对应的关联关系
        List<RoleMenu> menuList = roleMenuService.list(new LambdaQueryWrapper<RoleMenu>()
                .in(RoleMenu::getRoleId, roleIds));
        if (!CollectionUtils.isEmpty(menuList)) {
            throw new BusinessException(CalligraphyHttpStatus.CalligraphyErrorMessage.MENU_EMPTY_ERROR);
        }
        // 封装数据
        List<Long> menuIds = menuList
                .stream()
                .map(RoleMenu::getMenuId)
                .collect(Collectors.toList());

        List<Menu> menus =
                menuService.list(new LambdaQueryWrapper<Menu>()
                                .in(Menu::getMenuId, menuIds));
        return menus;
    }

    @Override
    public List<Menu> getUserMenu(Boolean isPerm) {
        User user = (User) SecurityUtils.getSubject().getPrincipal();
        Long userId = user.getUserId();
        List<UserRole> userRoles = userRoleService.list(
                new LambdaQueryWrapper<UserRole>()
                        .eq(UserRole::getUserId, userId));
        if (CollectionUtils.isEmpty(userRoles)) {
            return null;
        }
        List<Long> roleIds = userRoles.stream()
                .map(UserRole::getRoleId)
                .collect(Collectors.toList());

        List<RoleMenu> roleMenus = roleMenuService.list(
                new LambdaQueryWrapper<RoleMenu>()
                        .in(RoleMenu::getRoleId, roleIds));

        // 用户的菜单
        List<Long> menuIds = roleMenus
                .stream()
                .map(RoleMenu::getMenuId)
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(menuIds)) {
            return null;
        }

        LambdaQueryWrapper<Menu> menuQueryWrapper = new LambdaQueryWrapper<Menu>()
                .in(Menu::getMenuId, menuIds);
        // 如果是来自权限的话，就不允许为空
        if (isPerm) {
            menuQueryWrapper.isNotNull(Menu::getPerms);
        }else {
            menuQueryWrapper.isNull(Menu::getPerms);
        }
        List<Menu> menuList = menuService.list();
        return menuList;
    }

    @Override
    public void delete(Long id) {
        log.info("进来删除了用户.....");
    }


}
